package com.key.puzzlemodel.util

import android.content.ContentValues
import android.content.Context
import android.content.Intent
import android.graphics.*
import android.media.MediaScannerConnection
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.MediaStore
import android.view.View
import android.view.WindowManager
import android.webkit.WebView
import androidx.recyclerview.widget.RecyclerView
import kotlinx.coroutines.delay
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.util.*
import kotlin.collections.ArrayList
import java.lang.NullPointerException


/**
 *
 * @功能描述:     网页工具类
 * @创建时间:     2022/1/4
 * @创建者:       阳
 * @修改时间:     2022/1/4
 * @修改者:       阳
 */
object BitmapUtil {

    /**
     * 保存控件的能展示的内容，例如：webview的最后一页
     */
    fun getViewBitmapWithoutBottom(v: View?): Bitmap? {
        if (null == v) {
            return null
        }
        v.isDrawingCacheEnabled = true
        v.buildDrawingCache()
        v.measure(
            View.MeasureSpec.makeMeasureSpec(v.width, View.MeasureSpec.EXACTLY),
            View.MeasureSpec.makeMeasureSpec(v.height, View.MeasureSpec.EXACTLY)
        )
        v.layout(
            v.x.toInt(),
            v.y.toInt(),
            v.x.toInt() + v.measuredWidth,
            v.y.toInt() + v.measuredHeight
        )
        val bp: Bitmap = Bitmap.createBitmap(
            v.drawingCache,
            0,
            0,
            v.measuredWidth,
            v.measuredHeight - v.paddingBottom
        )
        v.isDrawingCacheEnabled = false
        v.destroyDrawingCache()

//        val bp: Bitmap = Bitmap.createBitmap(
//            v.drawingCache,
//            0,
//            0,
//            v.measuredWidth,
//            v.measuredHeight - v.paddingBottom
//        )
//        val canvas = Canvas(bp)
//        v.draw(canvas)
        return bp
    }

    /**
     * 保存控件的能展示的内容，例如：webview的每一页
     */
    fun getViewBitmap(v: View?): Bitmap? {
        if (null == v) {
            return null
        }

//        val bitmap = Bitmap.createBitmap(v.width, v.height, Bitmap.Config.RGB_565)
//        val canvas = Canvas(bitmap)
//        v.draw(canvas)

        v.isDrawingCacheEnabled = true
        v.buildDrawingCache()
        v.measure(
            View.MeasureSpec.makeMeasureSpec(v.width, View.MeasureSpec.EXACTLY),
            View.MeasureSpec.makeMeasureSpec(v.height, View.MeasureSpec.EXACTLY)
        )
        v.layout(
            v.x.toInt(),
            v.y.toInt(),
            v.x.toInt() + v.measuredWidth,
            v.y.toInt() + v.measuredHeight
        )
        val bitmap: Bitmap = Bitmap.createBitmap(
            v.drawingCache,
            0,
            0,
            v.measuredWidth,
            v.measuredHeight
        )
        v.isDrawingCacheEnabled = false
        v.destroyDrawingCache()
        return bitmap
    }


    /**
     * 保存webview的所有内容
     */
    suspend fun saveWebToBitmap(recyclerView: RecyclerView): Bitmap {
        //发起测量
        recyclerView.measure(0, 0)
        //获取测量后的高度
        val contentHeight = recyclerView.measuredHeight
        //获取webview的高度
        val height = recyclerView.height
        //计算滚动的次数
        val totalScrollCount = contentHeight / height
        //剩余的高度
        val surplusScrollHeight = contentHeight - (totalScrollCount * height)

        //存储图片的容器
        var cacheBitmapList = ArrayList<Bitmap>()

        recyclerView.scrollTo(0, 0)


        //循环保存bitmap
        for (index in 0..totalScrollCount) {
            if (index > 0) {
                //滚动webview
//                webView.scaleY = (index * height).toFloat()
                recyclerView.scrollTo(0, index * height)
                delay(200)
            }
            //获取截图
            var cacheBitmap = getViewBitmap(recyclerView)
            cacheBitmap?.let { cacheBitmapList.add(it) }
        }

        //如果不能整除,需要额外滚动一次
        if (surplusScrollHeight > 0) {
            //滚动webview
//            webView.scaleY = contentHeight.toFloat()
            recyclerView.scrollTo(0, contentHeight)
//            webView.scrollTo(0, totalScrollCount * height)
            //获取截图
            var cacheBitmap = getViewBitmapWithoutBottom(recyclerView)
            cacheBitmap?.let { cacheBitmapList.add(it) }
        }

        return mergeBitmap(cacheBitmapList, contentHeight, surplusScrollHeight)
    }


    private fun mergeBitmap(
        datas: ArrayList<Bitmap>,
        contentHeight: Int,
        surplusScrollHeight: Int
    ): Bitmap {
        //图纸宽度(因为是截图,图片宽度大小都是一样的)
        val bitmapWidth = datas[0].width
        //图纸高度 = WebView内容的高度
        val bitmapHeight: Int = contentHeight
        //1:创建图纸
        val bimap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.RGB_565)
        //2:创建画布,并绑定图纸
        val canvas = Canvas(bimap)
        //3:创建画笔
        val paint = Paint(Paint.ANTI_ALIAS_FLAG)
        val count: Int = datas.size
        var i = 0
        while (i < count) {
            val data = datas[i]
            val left = 0f
            val top = (i * data.height).toFloat()
            var src: Rect? = null
            var des: RectF? = null
            /**
             * Rect src = new Rect(); 代表图片矩形范围
             * RectF des = new RectF(); 代表Canvas的矩形范围(显示位置)
             */
            /**
             * Rect src = new Rect(); 代表图片矩形范围
             * RectF des = new RectF(); 代表Canvas的矩形范围(显示位置)
             */
            if (i == count - 1 && surplusScrollHeight > 0) {
                val srcRectTop: Int = data.height - surplusScrollHeight
                src = Rect(0, srcRectTop, data.width, data.height)
                des = RectF(left, top, data.width.toFloat(), top + surplusScrollHeight)
            } else {
                src = Rect(0, 0, data.width, data.height)
                des = RectF(left, top, data.width.toFloat(), top + data.height)
            }
            //绘制图片
            canvas.drawBitmap(data, src, des, paint)
            i++
        }


        //图片压缩
        val bos = ByteArrayOutputStream()
        bimap.compress(Bitmap.CompressFormat.JPEG, 100, bos)
        val bytes: ByteArray = bos.toByteArray()

        return BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
    }


    /**
     * get the width of screen
     */
    fun getScreenWidth(ctx: Context): Int {
        var w = 0
        w = if (Build.VERSION.SDK_INT > 13) {
            val p = Point()
            (ctx.getSystemService(Context.WINDOW_SERVICE) as WindowManager).defaultDisplay
                .getSize(p)
            p.x
        } else {
            (ctx.getSystemService(Context.WINDOW_SERVICE) as WindowManager).getDefaultDisplay()
                .getWidth()
        }
        return w
    }

    /**
     * 保存图片
     * @param context
     * @param bitmap
     * @param file
     * @param quality
     * @return
     */
    fun save(context: Context, bitmap: Bitmap?, file: File, quality: Int): Boolean {
        var quality = quality
        if (bitmap == null) return false
        // 获得后缀格式
        val abs: String = file.absolutePath
        val suffix = abs.substring(abs.lastIndexOf(".") + 1).toLowerCase()
        val format: Bitmap.CompressFormat
        if ("jpg" == suffix || "jpeg" == suffix) {
            format = Bitmap.CompressFormat.JPEG
        } else {
            format = Bitmap.CompressFormat.PNG
            quality = 100
        }
        return if (file.exists() && !file.delete()) false else try {
            val stream = FileOutputStream(file)
            bitmap.compress(format, quality, stream)
            stream.flush()
            stream.close()
            context.sendBroadcast(Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(file)))
            true
        } catch (e: Exception) {
            false
        }
    }


    fun savePuzzleBitmap(
        context: Context,
        bitmap: Bitmap,
        result: (state: Boolean, photoPath: String) -> Unit
    ) {
        val name = "puzzle_${System.currentTimeMillis()}.jpeg"
        if (com.key.puzzlemodel.config.PuzzleConfig.IsSavePublicDirectory) { //保存到公共目录
            if (bitmap2PicturesFolder(
                    context,
                    bitmap,
                    com.key.puzzlemodel.config.PuzzleConfig.PHOTO_SAVE_PATH,
                    name
                )
            ) {
                val photoFile =
                    "${Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)}${File.separator}${com.key.puzzlemodel.config.PuzzleConfig.PHOTO_SAVE_PATH}${File.separator}$name"

                result.invoke(true, photoFile)
            } else {
                result.invoke(false, "")
            }
        } else {  //保存到私有目录
            if (bitmapPrivateFolder(
                    context,
                    bitmap,
                    com.key.puzzlemodel.config.PuzzleConfig.PHOTO_SAVE_PATH,
                    name
                )
            ) {
                result.invoke(
                    true,
                    com.key.puzzlemodel.config.PuzzleConfig.PHOTO_SAVE_PATH + "/" + name
                )
            } else {
                result.invoke(false, "")
            }
        }
    }


    /**
     * 保存照片到【共享存储空间DICM/】下
     *
     * 【Android 10以下】使用Java I/O方式将图片保存到指定文件夹，保存成功后，系统相册不会显示该图片，需手动通知相册刷新
     * 【Android 10及以上】使用MediaStore的方式将图片保存到指定文件夹，保存成功后，系统相册会显示该图片
     *
     * @param context 上下文
     * @param bitmap 图片
     * @param relativePath 从Pictures/开始的相对路径，eg：A/B，表示存储在SDCard根目录Pictures/A/B/目录下
     * @param name 文件名称  aa.png  aa,jpg
     * @return
     */
    private fun bitmap2PicturesFolder(
        context: Context,
        bitmap: Bitmap,
        relativePath: String,
        name: String
    ): Boolean {
        var result = false
        var mimeType = "image/jpeg"
        if (name.toLowerCase(Locale.getDefault()) == "png") {
            mimeType = "image/png"
        }

        if (Build.VERSION_CODES.Q > Build.VERSION.SDK_INT) {// Android 10以下
            val path =
                "${Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)}${File.separator}$relativePath${File.separator}"

            result = bitmap2File(bitmap, path, name)

            // 扫描新增加的图片到相册
            MediaScannerConnection.scanFile(
                context, arrayOf("${path}$name"), arrayOf(mimeType)
            ) { path1, uri ->

                //Log.d("保存照片", "path = $path1, uri = $uri")
            }
        } else {// Android 10及以上
            val values = ContentValues().apply {
                put(MediaStore.Images.Media.DISPLAY_NAME, name)
                put(MediaStore.Images.Media.MIME_TYPE, mimeType)
                put(
                    MediaStore.Images.Media.RELATIVE_PATH,
                    "${Environment.DIRECTORY_DCIM}${File.separator}$relativePath${File.separator}"
                )
            }
            try {
                val uri =
                    context.contentResolver.insert(
                        MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                        values
                    )

                val out = context.contentResolver.openOutputStream(uri!!)
                if ("image/png" == mimeType) {
                    bitmap.compress(Bitmap.CompressFormat.PNG, 100, out)
                } else {
                    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out)
                }
                out?.flush()
                out?.close()
                result = true
            } catch (e: IOException) {
                result = false
                e.printStackTrace()
            }
        }
        return result
    }


    /**
     * 保存照片到私有目录下
     *
     * 【Android 10以下】使用Java I/O方式将图片保存到指定文件夹，保存成功后，系统相册不会显示该图片，需手动通知相册刷新
     * 【Android 10及以上】使用MediaStore的方式将图片保存到指定文件夹，保存成功后，系统相册会显示该图片
     *
     * @param context 上下文
     * @param bitmap 图片
     * @param savePath  私有目录路径
     * @param name 文件名称  aa.png  aa,jpg
     * @return
     */
    private fun bitmapPrivateFolder(
        context: Context,
        bitmap: Bitmap,
        savePath: String,
        name: String
    ): Boolean {
        var result = false
        var mimeType = "image/jpeg"
        if (name.toLowerCase(Locale.getDefault()) == "png") {
            mimeType = "image/png"
        }
        //Log.e("保存照片", "保存路径：$savePath")
        result = bitmap2File(bitmap, savePath, name)
//        // 扫描新增加的图片到相册
//        MediaScannerConnection.scanFile(
//            context, arrayOf("${savePath}$name"), arrayOf(mimeType)
//        ) { path1, uri ->
//
//            // Log.d("保存照片", "path = $path1, uri = $uri")
//        }
        return result
    }

    /**
     * 保存Bitmap到文件
     * @param bitmap 图片数据
     * @param path 文件路径
     * @param name 文件名称
     * @return
     */
    private fun bitmap2File(bitmap: Bitmap, path: String, name: String): Boolean {
        var result = false

        // 检查路径是否存在，不存在创建之
        val file = File(path)
        if (!file.exists()) {
            file.mkdirs()
        }

        // 文件已存在，删除之
        val imageFile = File(file, name)
        if (imageFile.exists()) {
            imageFile.delete()
        }

        var format = Bitmap.CompressFormat.JPEG
        if (name.toLowerCase(Locale.getDefault()).endsWith("png")) {
            format = Bitmap.CompressFormat.PNG
        }

        try {
            imageFile.createNewFile()
            val fos = FileOutputStream(imageFile)
            bitmap.compress(format, 100, fos)
            fos.flush()
            fos.close()
            result = true
        } catch (e: IOException) {
            e.printStackTrace()
        }
        return result
    }


    /**
     * 截取WebView的屏幕，
     *
     * webView.capturePicture()方法在android 4.4（19）版本被废弃，
     *
     * 官方建议通过onDraw(Canvas)截屏
     *
     * @param webView
     * @return
     */
    fun captureWebView(webView: WebView): Bitmap? {
        val snapShot = webView.capturePicture()
        val bitmap = Bitmap.createBitmap(
            snapShot.width,
            snapShot.height, Bitmap.Config.RGB_565
        )

        //限制大小
        val bitSize = 1024 * 1024 * 60
        //Log.e("图片大小：", " -- ${getBitmapSize(bitmap)}")

        if (getBitmapSize(bitmap) > bitSize) {
            return null
        }

        val canvas = Canvas(bitmap)
        snapShot.draw(canvas)

        return bitmap
    }


    fun captureWebViewToBitmap(webView: WebView): Bitmap? {

        var bitmap = Bitmap.createBitmap(webView.width, webView.height, Bitmap.Config.ARGB_8888)

        var canvas = Canvas(bitmap)

        webView.draw(canvas)

        return bitmap
    }


    /**
     * 得到bitmap的大小
     */
    fun getBitmapSize(bitmap: Bitmap): Int {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {    //API 19
            return bitmap.allocationByteCount
        }
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) { //API 12
            bitmap.byteCount
        } else bitmap.rowBytes * bitmap.height
        // 在低版本中用一行的字节x高度
        //earlier version
    }


    fun getDrawingBitmap(
        paddingLeft: Int,
        paddingTop: Int,
        paddingRight: Int,
        paddingBottom: Int,
        roundRadius: Int,
        widthOrHeight: Int,
        direction: Int,
        bitmap: Bitmap,
        backgroundColor: Int,
        rectF: RectF
    ): Bitmap {

        // 最终生成Bitmap的宽高
        var width: Int
        var height: Int

        // 图片显示区域的宽高比
        val ratio = rectF.width() * bitmap.width / (rectF.height() * bitmap.height)

        // 计算图片宽高
        if (0 == direction) { // 竖直方向
            width = widthOrHeight
            height = (width / ratio).toInt()
        } else { // 水平方向
            height = widthOrHeight
            width = (height * ratio).toInt()
        }

        // 加上边距
        width += paddingLeft + paddingRight
        height += paddingTop + paddingBottom

        // 使用原图进行绘制，避免重复创建新的Bitmap，降低OOM概率
        val widthReal = (width - paddingLeft - paddingRight).toFloat()
        val scale = widthReal / (rectF.width() * bitmap.width)
        val dx = rectF.left * bitmap.width * scale
        val dy = rectF.top * bitmap.height * scale
        val matrix = Matrix()
        matrix.setScale(scale, scale)
        matrix.postTranslate(-dx + paddingLeft, -dy + paddingTop)

        // 绘制开始
        val result = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565)
        val canvas = Canvas(result)
        canvas.drawColor(backgroundColor);
        val paint = Paint()
        paint.isAntiAlias = true
        val layerId = canvas.saveLayer(
            paddingLeft.toFloat(),
            paddingTop.toFloat(),
            (width - paddingRight).toFloat(),
            (height - paddingBottom).toFloat(),
            paint,
            Canvas.ALL_SAVE_FLAG
        )
        canvas.drawRoundRect(
            paddingLeft.toFloat(),
            paddingTop.toFloat(),
            (width - paddingRight).toFloat(),
            (height - paddingBottom).toFloat(),
            roundRadius.toFloat(),
            roundRadius.toFloat(),
            paint
        )
        paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP) // 处理圆角
        canvas.drawBitmap(bitmap, matrix, paint)
        paint.xfermode = null
        canvas.restoreToCount(layerId)
        return result
    }

    /**
     * 图片列表合成图片
     */
    fun bitmapListToBitmap(
        bitmapList: ArrayList<Bitmap>,
        contentWidth: Int,
        contentHeight: Int,
        isVertical: Boolean = true,
    ): Bitmap {
        //根据计算出的recyclerView高度创建bitmap
        val bigBitmap = Bitmap.createBitmap(contentWidth, contentHeight, Bitmap.Config.RGB_565)
        //创建一个canvas画板
        val canvas = Canvas(bigBitmap)
        //画出recyclerView的背景色
        //canvas.drawColor(backgroundColor)
        //当前bitmap的高度
        var top = 0
        var left = 0

        //画笔
        val paint = Paint()
        for (i in 0 until bitmapList.size) {
            val bitmap = bitmapList[i]
            //Log.e("图片列表合成图片", " 合成次数：$i")
            if (isVertical) {
                canvas.drawBitmap(bitmap, 0f, top.toFloat(), paint)
                top += bitmap.height
            } else {
                canvas.drawBitmap(bitmap, left.toFloat(), 0f, paint)
                left += bitmap.width
            }
        }
        return bigBitmap
    }


    /**
     * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
     */
    fun dip2px(context: Context, dpValue: Float): Int {
        val scale = context.resources.displayMetrics.density
        return (dpValue * scale + 0.5f).toInt()
    }

    /**
     * 利用BitmapShader绘制圆角图片
     *
     * @param bitmap    待处理图片
     * @param outWidth  结果图片宽度，一般为控件的宽度
     * @param outHeight 结果图片高度，一般为控件的高度
     * @param radius    圆角半径大小
     * @return 结果图片
     */
    private fun roundBitmapByShader(
        bitmap: Bitmap?,
        outWidth: Int,
        outHeight: Int,
        radius: Int
    ): Bitmap? {
        if (bitmap == null) {
            throw NullPointerException("Bitmap can't be null")
        }
        // 初始化缩放比
        val widthScale = outWidth * 1.0f / bitmap.width
        val heightScale = outHeight * 1.0f / bitmap.height
        val matrix = Matrix()
        matrix.setScale(widthScale, heightScale)
        // 初始化绘制纹理图
        val bitmapShader = BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
        // 根据控件大小对纹理图进行拉伸缩放处理
        bitmapShader.setLocalMatrix(matrix)
        // 初始化目标bitmap
        val targetBitmap = Bitmap.createBitmap(outWidth, outHeight, Bitmap.Config.ARGB_8888)
        // 初始化目标画布
        val targetCanvas = Canvas(targetBitmap)
        // 初始化画笔
        val paint = Paint()
        paint.isAntiAlias = true
        paint.shader = bitmapShader

        var left = 0f

        // 利用画笔将纹理图绘制到画布上面
        targetCanvas.drawRoundRect(
            RectF(left, left, outWidth.toFloat(), outWidth.toFloat()),
            radius.toFloat(), radius.toFloat(), paint
        )
        return targetBitmap
    }


    private fun toRoundBitmap(bitmap: Bitmap, radius: Float): Bitmap? {
        val bm = Bitmap.createBitmap(bitmap.width, bitmap.height, Bitmap.Config.ARGB_8888)
        val canvas = Canvas(bm)
        val paint = Paint(Paint.ANTI_ALIAS_FLAG)
        paint.isAntiAlias = true
        // 这里需要先画出一个圆
//        canvas.drawCircle(
//            (bitmap.width / 2).toFloat(),
//            (bitmap.height / 2).toFloat(), (bitmap.width / 2).toFloat(), paint
//        )

        var left = 0f

        canvas.drawRoundRect(
            RectF(left, left, bitmap.width.toFloat(), bitmap.height.toFloat()),
            radius, radius, paint
        )


        // 圆画好之后将画笔重置一下
        paint.reset()
        // 设置图像合成模式，该模式为只在源图像和目标图像相交的地方绘制源图像
        paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)
        canvas.drawBitmap(bitmap, 0f, 0f, paint)
        return bm
    }
}